#pragma once

#include "Sock.hpp"
#include <iostream>
#include <string>
#include <cstring>
#include <jsoncpp/json/json.h>


namespace ns_protocal
{
// #define SPACE " "
// #define SPACE_LEN strlen(SPACE)

#define SEP "/r/n"
#define SEP_LEN strlen(SEP)

//#define MYSELF 1

    class Request
    {
    public:
        std::string Serialiaze()
        {
#ifdef MYSELF
            std::string str;
            str += std::to_string(x_);
            str += SEP;
            str += op_;
            str += SEP;
            str += std::to_string(y_);
            return str;
#else
            Json::Value root;
            root["x"] = x_;
            root["y"] = y_;
            root["op"] = op_;
            Json::FastWriter writer;
            return writer.write(root);
#endif
        }

        bool Deserialized(const std::string &str)
        {
#ifdef MYSELF
            std::size_t left = str.find(SEP);
            if (left == str.npos)
                return false;
            std::size_t right = str.rfind(SEP);
            if (right == str.npos)
                return false;

            x_ = atoi(str.substr(0, left).c_str());
            y_ = atoi(str.substr(right + SEP_LEN).c_str());
            if (left + SEP_LEN > str.size())
                return false;
            else
                op_ = str[left + SEP_LEN];
            return true;

#else
            Json::Value root;
            Json::Reader reader;
            reader.parse(str,root);
            x_ = root["x"].asInt();
            y_ = root["y"].asInt();
            op_ = root["op"].asInt();
            return true;
#endif
        }

        Request() = default;
        Request(int x, int y, char op)
            : x_(x), y_(y), op_(op)
        {
        }

    public:
        int x_;
        int y_;
        char op_;
    };

    class Response
    {
    public:
        Response() {}
        Response(int rest, int code,int x,int y,int op)
            : result_(rest), code_(code),x_(x),y_(y),op_(op)
        {
        }

        std::string Serialiaze()
        {
#ifdef MYSELF
            std::string str;
            str += std::to_string(code_);
            str += SEP;
            str += std::to_string(result_);
            return str;
#else
            Json::Value root;
            root["result"] = result_;
            root["code"] = code_;
            root["xx"] = x_;
            root["yy"] = y_;
            root["op"] = op_;

            Json::FastWriter writer;
            return writer.write(root);
#endif
        }

        bool Deserialized(const std::string &str)
        {
#ifdef MYSELF
            std::size_t pos = str.find(SEP);
            if (pos == str.npos)
                return false;
            code_ = atoi(str.substr(0, pos).c_str());
            result_ = atoi(str.substr(pos + SEP_LEN).c_str());
            return true;

#else
            Json::Value root;
            Json::Reader reader;
            reader.parse(str,root);
            result_ = root["result"].asInt();
            code_ = root["code"].asInt();
            x_ = root["xx"].asInt();
            y_ = root["yy"].asInt();
            op_ = root["op"].asInt();
            return true;
#endif
        }

    public:
        int result_;
        int code_;
        int x_;
        int y_;
        int op_;
    };

    bool Recv(int sock,std::string *out)
    {
        char buffer[256];
        ssize_t s = recv(sock, buffer, sizeof(buffer)-1, 0);
        if (s > 0)
        {
            buffer[s] = 0;
            *out +=buffer;   

        }
        else if(s==0)
        {
            std::cout<<"client quit"<<std::endl;
            return false;
        }
        else
        {
            std::cout<<"recv error"<<std::endl;
            return false;
        }
        return true;
    }

    void Send(int sock, const std::string str)
    {
        //std::cout<< "send in"<<std::endl;
        int n = send(sock, str.c_str(), str.size(), 0);
        if(n<0)
        {
            std::cout<<"send error"<<std::endl;
        }
    }

    std::string Decode(std::string &buffer)
    {
        std::size_t pos = buffer.find(SEP);
        if(pos == buffer.npos)
            return "";

        int size = atoi(buffer.substr(0,pos).c_str());
        int surplus = buffer.size()-2*SEP_LEN-pos;
        if(surplus>=size)
        {
            buffer.erase(0,pos+SEP_LEN);
            std::string s = buffer.substr(0,size);
            buffer.erase(0,SEP_LEN);
            return s;
        }
        else
            return "";
    }

    std::string Encode(std::string& s)
    {
        std::string new_package = std::to_string(s.size());
        new_package +=SEP;
        new_package +=s;
        new_package +=SEP;
        return new_package;
    }

}